package com.quanxiaoha.weblog.common.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.quanxiaoha.weblog.common.domain.dos.ArticleCategoryRelDo;
import com.quanxiaoha.weblog.common.domain.entity.Article;
import com.quanxiaoha.weblog.common.domain.entity.ArticleCategoryRel;
import com.quanxiaoha.weblog.common.domain.entity.ArticleContent;
import com.quanxiaoha.weblog.common.domain.entity.Category;
import com.quanxiaoha.weblog.common.domain.mapper.ArticleCategoryRelMapper;
import com.quanxiaoha.weblog.common.domain.mapper.ArticleContentMapper;
import com.quanxiaoha.weblog.common.domain.mapper.ArticleMapper;
import com.quanxiaoha.weblog.common.domain.mapper.CategoryMapper;
import com.quanxiaoha.weblog.common.domain.query.ArticleListQuery;
import com.quanxiaoha.weblog.common.domain.query.ArticleQuery;
import com.quanxiaoha.weblog.common.domain.query.CategoryQuery;
import com.quanxiaoha.weblog.common.domain.query.CountQuery;
import com.quanxiaoha.weblog.common.domain.vo.ArticleCategoryRelVo;
import com.quanxiaoha.weblog.common.domain.vo.ArticleVo;
import com.quanxiaoha.weblog.common.domain.vo.CategoryVo;
import com.quanxiaoha.weblog.common.domain.vo.ReadNumVo;
import com.quanxiaoha.weblog.common.service.IScheduleArticleService;
import com.quanxiaoha.weblog.common.service.IScheduleRewardService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 文章表 服务实现类
 * </p>
 *
 * @author Roy
 * @since 2025-06-02
 */
@Service
public class ScheduleArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IScheduleArticleService {

    // 配置保存目录（实际使用时应放入application.properties）
    @Value("${pic.upload_dir}")
    private String UPLOAD_DIR = "uploads/";

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private ArticleCategoryRelMapper articleCategoryRelMapper;

    @Autowired
    private ArticleContentMapper articleContentMapper;

    @Autowired
    private IScheduleRewardService scheduleRewardService;


    @Override
    public List<CategoryVo> categoryList() {

        List<CategoryVo> categoryVos = BeanUtil.copyToList(categoryMapper.selectList(null), CategoryVo.class);
        return buildTreeStream(categoryVos);
    }

    @Override
    public List<ArticleCategoryRelVo> getNumList() {

        List<ArticleCategoryRelDo> nums = articleCategoryRelMapper.getNums();
        Map<Integer, List<ArticleCategoryRelDo>> map = nums.stream().collect(Collectors.groupingBy(ArticleCategoryRelDo::getCategoryId));
        List<ArticleCategoryRelVo> articleCategoryRelVos = new ArrayList<>();
        map.forEach((k, v) -> {
            ArticleCategoryRelVo articleCategoryRelVo = new ArticleCategoryRelVo();
            articleCategoryRelVo.setId(k);
            Integer count = (int)v.stream().filter(x -> x.getReadNum() < 5).count();
            articleCategoryRelVo.setNewNum(count);
            articleCategoryRelVo.setReadNum(v.size());
            List<Long> collect = v.stream().map(x -> x.getReadNum()).collect(Collectors.toList());
            double avg = kahanAverage(collect);
            articleCategoryRelVo.setAvgReadNum(avg);
            articleCategoryRelVos.add(articleCategoryRelVo);
        });
        return articleCategoryRelVos;
    }


    public static double kahanAverage(List<Long> data) {
        double sum = 0.0;
        double compensation = 0.0;  // 误差补偿
        for (double value : data) {
            double y = value - compensation;
            double t = sum + y;
            compensation = (t - sum) - y;  // 计算本次舍入误差
            sum = t;
        }
        BigDecimal bd = new BigDecimal(sum / data.size())
                .setScale(1, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }

    public static List<CategoryVo> buildTreeStream(List<CategoryVo> nodes) {
        // 按pid分组
        Map<Integer, List<CategoryVo>> groupByPid = nodes.stream()
                .filter(node -> node.getPid() != 0)
                .collect(Collectors.groupingBy(CategoryVo::getPid));

        // 设置子节点
        nodes.forEach(node -> {
            List<CategoryVo> children = groupByPid.getOrDefault(node.getId(), Collections.emptyList());
            node.setChildren(children);
        });

        // 返回根节点
        return nodes.stream()
                .filter(node -> node.getPid() == 0)
                .collect(Collectors.toList());
    }

    @Override
    public void saveCategory(CategoryQuery query) {

        Category category = BeanUtil.copyProperties(query, Category.class);
        if (query.getId()!= null) {
            categoryMapper.updateById(category);
        } else {
            categoryMapper.insert(category);
        }
    }

    @Override
    public void deleteCategory(Integer query) {
        categoryMapper.deleteById(query);
    }

    @Override
    public Page<ArticleVo> articleList(ArticleListQuery query) {

        Page<ArticleVo> page = new Page<>(query.getPageNum(), query.getPageSize());

        List<Integer> categoryIds = null;
        if (query.getCategoryId() != null) {
            categoryIds = articleCategoryRelMapper.selectList(new QueryWrapper<ArticleCategoryRel>().eq("category_id", query.getCategoryId()))
                    .stream().map(ArticleCategoryRel::getArticleId).collect(Collectors.toList());
        }
        if (categoryIds == null || categoryIds.isEmpty()) {
            return new Page<>();
        }
        Page<ArticleVo> Article = baseMapper.articlePage(page,categoryIds,query.getTitle());

        return Article;
    }

    @Override
    public ArticleVo saveArticle(ArticleQuery query) {

        Article article  =  BeanUtil.copyProperties(query, Article.class);
        if (query.getId() != null) {

            //保存文章
            this.updateById(article);

            //保存文章内容
            ArticleContent articleContent = articleContentMapper.selectOne(new QueryWrapper<ArticleContent>().eq("article_id", query.getId()));
            articleContent.setContent(query.getContent());
            articleContentMapper.updateById(articleContent);

            //保存文章分类关联关系
            ArticleCategoryRel articleCategoryRel = articleCategoryRelMapper.selectOne(new QueryWrapper<ArticleCategoryRel>().eq("article_id", query.getId()));
            articleCategoryRel.setCategoryId(query.getCategoryId());
            articleCategoryRelMapper.updateById(articleCategoryRel);

            ArticleVo articleVo = BeanUtil.copyProperties(article, ArticleVo.class);
            articleVo.setCategoryId(query.getCategoryId());
            articleVo.setContent(articleContent.getContent());
            return articleVo;
        } else {

            //保存文章
            this.save(article);

            //保存文章内容
            ArticleContent articleContent = new ArticleContent();
            articleContent.setArticleId(article.getId());
            articleContent.setContent(query.getContent());
            articleContentMapper.insert(articleContent);

            //保存文章分类关联关系
            ArticleCategoryRel articleCategoryRel = new ArticleCategoryRel();
            articleCategoryRel.setArticleId(article.getId());
            articleCategoryRel.setCategoryId(query.getCategoryId());
            articleCategoryRelMapper.insert(articleCategoryRel);

            ArticleVo articleVo = BeanUtil.copyProperties(article, ArticleVo.class);
            articleVo.setCategoryId(query.getCategoryId());
            articleVo.setContent(articleContent.getContent());
            return articleVo;
        }
    }

    @Override
    public void deleteArticle(Integer query) {
        this.removeById(query);
        articleContentMapper.delete(new QueryWrapper<ArticleContent>().eq("article_id", query));

    }

    @Override
    public ReadNumVo clock(Integer id) {

        ReadNumVo readNumVo = new ReadNumVo();
        Article article = this.getById(id);
        if (article == null) return null;

        article.setReadNum(article.getReadNum() + 1);
        this.updateById(article);
        readNumVo.setReadNum(article.getReadNum());
        Integer reward = 0;
        try {
            reward = scheduleRewardService.saveHabitReward();
            String rewardStr;
            switch (reward){
                case 0:
                    rewardStr = "很遗憾没有获得积分";
                    break;
                case 1:
                    rewardStr = "恭喜你获得了"+reward+"积分";
                    break;
                case 2:
                    rewardStr = "恭喜你获得了"+reward+"积分";
                    break;
                case 7:
                    rewardStr = "恭喜你获得了游龙积分";
                    break;
                case 9:
                    rewardStr = "恭喜你获得了至尊积分";
                    break;
                case 10:
                    rewardStr = "恭喜你获得了球王积分";
                    break;
                default:
                    rewardStr = "很遗憾没有获得积分";
            }
            readNumVo.setReward(rewardStr);
        }catch (Exception e) {
            e.printStackTrace();
        }

        return readNumVo;
    }

    @Override
    public String upload(MultipartFile file) throws Exception {

        // 1. 校验文件是否为空
        if (file.isEmpty()) {
            throw new Exception("文件不能为空");
        }

        // 2. 校验文件类型[1,3](@ref)
        String contentType = file.getContentType();
        if (!"image/jpeg".equals(contentType) &&
                !"image/png".equals(contentType) &&
                !"image/gif".equals(contentType)) {
            throw new Exception("仅支持JPG/PNG/GIF格式");
        }

        try {
            // 3. 创建唯一文件名[1,4](@ref)
            String originalName = file.getOriginalFilename();
            String extension = originalName.substring(originalName.lastIndexOf("."));
            String newFileName = UUID.randomUUID() +"_"+ originalName;

            // 4. 创建目标目录[3,4](@ref)
            Path uploadPath = Paths.get(UPLOAD_DIR);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }

            // 5. 保存文件[1,5](@ref)
            Path filePath = uploadPath.resolve(newFileName);
            file.transferTo(filePath);

            return newFileName;

        } catch (IOException e) {
            throw new Exception("上传失败: " + e.getMessage());
        }
    }

    @Override
    public ArticleVo getCategory() {

        // 1. 获取总记录数
        long total = articleContentMapper.selectCount(null);

        // 2. 生成随机偏移量（0 到 total-1）
        int offset = new Random().nextInt((int) total);

        // 3. 通过QueryWrapper设置偏移量
        QueryWrapper<ArticleContent> wrapper = new QueryWrapper<>();
        wrapper.last("LIMIT " + offset + ", 1"); // 关键：动态追加LIMIT子句

        ArticleContent articleContent = articleContentMapper.selectOne(wrapper);
        if (articleContent == null) return null;
        Article byId = this.getById(articleContent.getArticleId());
        if (byId == null) return null;

        ArticleVo articleVo = BeanUtil.copyProperties(byId, ArticleVo.class);
        articleVo.setContent(articleContent.getContent());

        ArticleCategoryRel articleId = articleCategoryRelMapper.selectOne(new QueryWrapper<ArticleCategoryRel>().eq("article_id", articleContent.getArticleId()));
        if (articleId == null) return null;
        Category category = categoryMapper.selectById(articleId.getCategoryId());
        articleVo.setCategoryName(category.getName());
        articleVo.setTitle(category.getName()+" | "+articleVo.getTitle());
        return articleVo;
    }
}
